/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.model.command;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.gef.commands.Command;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.Lifeline;

/**
 * Takes a lifeline and a list of Interaction Fragments and ensures that the
 * lifeline if covered by (exactly) those fragments.
 * 
 * <p>
 * The following attributes must be set for the command to execute successfully:
 * </p>
 * <ul>
 * <li>Lifeline
 * <li>CoveredBy (must be non-null but can be an empty list)
 * </ul>
 * 
 * @author frankd@ifi.uio.no
 * 
 * @see UncoveredByCommand
 */
public class CoveredByCommand extends Command {

	/** The lifeline that is to be "covered". */
	private Lifeline lifeline;

	/**
	 * When the command has executed, the lifeline will be covered by only and
	 * all the interaction fragments specified in this list, and in the same
	 * order.
	 */
	private List<InteractionFragment> newCoveredBy, oldCoveredBy;

	public CoveredByCommand() {
	}

	public CoveredByCommand(final Lifeline lifeline,
			final List<InteractionFragment> coveredBy) {
		setLifeline(lifeline);
		setCoveredBy(coveredBy);
	}

	public void setLifeline(final Lifeline lifeline) {
		this.lifeline = lifeline;
	}

	public void setCoveredBy(final List<InteractionFragment> coveredBy) {
		this.newCoveredBy = coveredBy;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void execute() {
		oldCoveredBy = new ArrayList(lifeline.getCoveredBys().size());
		oldCoveredBy.addAll(lifeline.getCoveredBys());
		doCover(newCoveredBy);
	}

	@Override
	public void undo() {
		doCover(oldCoveredBy);
		oldCoveredBy = null;
	}

	@Override
	public void redo() {
		this.execute();
	}

	@SuppressWarnings("unchecked")
	private void doCover(List<InteractionFragment> coveredBy) {
		// remove obsolete fragments
		List toRemove = new ArrayList(coveredBy.size());
		for (InteractionFragment f : (List<InteractionFragment>) lifeline
				.getCoveredBys()) {
			if (!coveredBy.contains(f))
				toRemove.add(f);
		}
		lifeline.getCoveredBys().removeAll(toRemove);

		// shuffle existing and add new fragments
		int currentIndex = 0;
		for (InteractionFragment f : coveredBy) {
			int oldIndex = lifeline.getCoveredBys().indexOf(f);
			if (oldIndex == -1)
				lifeline.getCoveredBys().add(currentIndex, f);
			else if (oldIndex > currentIndex)
				lifeline.getCoveredBys().move(currentIndex, oldIndex);
			currentIndex++;
		}

		// Debugging
		// String covering = "";
		// for (InteractionFragment elem : coveredBy)
		// covering += elem.getName() + ", ";
	}

	@Override
	public void dispose() {
		lifeline = null;
		newCoveredBy = null;
		oldCoveredBy = null;
	}
}
